package com.eshop.inventory.thread;

import com.eshop.inventory.request.ProductInventoryCacheRefreshRequest;
import com.eshop.inventory.request.ProductInventoryDBUpdateRequest;
import com.eshop.inventory.request.Request;
import com.eshop.inventory.request.RequestQueue;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: Xukai
 * @description: 执行请求的工作线程
 * @createDate: 2018/7/23 12:58
 * @modified By:
 */
@Slf4j
public class RequestProcessorThread implements Callable<Boolean> {

    /**
     * 自己监控的内存队列
     */
    private ArrayBlockingQueue<Request> queue;

    public RequestProcessorThread(ArrayBlockingQueue<Request> queue) {
        this.queue = queue;
    }

    @Override
    public Boolean call() {
        try {
            while (true) {
                // ArrayBlockingQueue
                // Blocking就是说明，如果队列是空的，那么都会在执行操作的时候阻塞住
                Request request = queue.take();
                // 做读请求的去重
                // 为什么要在这里做读请求去重而不是在将请求加入队列时做去重
                // 过程：添加请求到队列 ===> 取出请求 ===> 执行请求
                // 如果将去重操作放在添加队列操作前，添加队列操作还属于多线程并发操作部分
                // 这种情况下可能造成flag误判，将去重放在执行请求操作前
                // 对flag的判断是单线程的，所以不可能发生flag的误判
                RequestQueue requestQueue = RequestQueue.getInstance();
                ConcurrentHashMap<Integer, Boolean> flagMap = requestQueue.getFlagMap();
                log.info("内存队列中ProductId的标志位状态：{}", flagMap.get(request.getProductId()));
                if (request instanceof ProductInventoryDBUpdateRequest) {
                    flagMap.put(request.getProductId(), true);
                } else if (request instanceof ProductInventoryCacheRefreshRequest) {
                    Boolean flag = flagMap.get(request.getProductId());
                    // 如果flag是null
                    if (flag == null) {
                        flagMap.put(request.getProductId(), false);
                        // 如果是缓存刷新的请求，那么就判断，如果标识不为空，而且是true，就说明之前有一个这个商品的数据库更新请求
                    } else if (flag) {
                        flagMap.put(request.getProductId(), false);
                    } else if (!flag) {
                        // 对于这种读请求，直接就过滤掉，不执行
                        continue;
                    }
                }
                // 执行这个request操作
                log.info("工作线程处理缓存更新请求，商品id={}", request.getProductId());
                request.process();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }
}
